package com.app.oral.service

import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.databind.ObjectMapper
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.web.client.RestTemplate
import org.springframework.web.multipart.MultipartFile
import java.io.IOException

@Service
class WeChatCloudStorageService {
    
    private val logger = LoggerFactory.getLogger(WeChatCloudStorageService::class.java)
    private val restTemplate = RestTemplate()
    private val objectMapper = ObjectMapper()
    private val httpClient = OkHttpClient()
    
    @Value("\${wechat.cloud.env}")
    private lateinit var env: String
    
    @Value("\${wechat.cloud.container-name}")
    private lateinit var containerName: String
    
    data class UploadCredentialRequest(
        val env: String,
        val path: String
    )
    
    data class UploadCredentialResponse(
        @field:JsonProperty("errcode") val errcode: Int = -1,
        @field:JsonProperty("errmsg") val errmsg: String? = null,
        @field:JsonProperty("url") val url: String? = null,
        @field:JsonProperty("token") val token: String? = null,
        @field:JsonProperty("authorization") val authorization: String? = null,
        @field:JsonProperty("file_id") val fileId: String? = null,
        @field:JsonProperty("cos_file_id") val cosFileId: String? = null
    )
    
    data class FileUploadResult(
        val success: Boolean,
        val message: String,
        val fileId: String? = null,
        val cosFileId: String? = null,
        val url: String? = null
    )
    
    /**
     * 上传音频文件到微信云托管
     */
    fun uploadAudioFile(file: MultipartFile, originalFileName: String): FileUploadResult {
        try {
            // 生成对象存储路径：直接存储到exam_audio目录
            val storagePath = "exam_audio/${System.currentTimeMillis()}_$originalFileName"
            logger.info("开始上传音频文件到路径: $storagePath")
            
            // 1. 获取上传凭证
            val credential = getUploadCredential(storagePath)
            if (credential.errcode != 0) {
                logger.error("获取上传凭证失败: ${credential.errmsg}")
                return FileUploadResult(false, credential.errmsg ?: "获取上传凭证失败")
            }

            // 2. 上传文件
            val uploadResult = uploadFileWithCredential(file, storagePath, credential)
            
            if (uploadResult.success) {
                logger.info("文件上传成功: $storagePath, fileId: ${uploadResult.fileId}")
            } else {
                logger.error("文件上传失败: $storagePath, 错误: ${uploadResult.message}")
            }
            
            return uploadResult
        } catch (e: Exception) {
            logger.error("上传文件异常: $originalFileName", e)
            return FileUploadResult(false, "上传文件异常: ${e.message}")
        }
    }
    
    /**
     * 获取上传凭证 - 使用OkHttp3
     */
    private fun getUploadCredential(path: String): UploadCredentialResponse {
        val url = "http://api.weixin.qq.com/tcb/uploadfile"
        
        val requestBody = UploadCredentialRequest(
            env = env,
            path = path
        )
        
        val json = objectMapper.writeValueAsString(requestBody)
        val body = json.toRequestBody("application/json".toMediaType())
        
        val request = Request.Builder()
            .url(url)
            .post(body)
            .addHeader("Content-Type", "application/json")
            .addHeader("Accept", "application/json")
            .build()
        
        try {
            logger.info("请求微信API: $url, body: $json")
            
            httpClient.newCall(request).execute().use { response ->
                val responseBody = response.body?.string()
                
                logger.info("微信API响应状态: ${response.code}")
                logger.info("微信API响应内容: $responseBody")
                
                if (!response.isSuccessful) {
                    return UploadCredentialResponse(-1, "HTTP错误: ${response.code} ${response.message}", null, null, null, null, null)
                }
                
                if (responseBody.isNullOrBlank()) {
                    return UploadCredentialResponse(-1, "响应体为空", null, null, null, null, null)
                }
                
                // 手动解析JSON
                return try {
                    objectMapper.readValue(responseBody, UploadCredentialResponse::class.java)
                } catch (e: Exception) {
                    logger.error("解析JSON响应失败: $responseBody", e)
                    UploadCredentialResponse(-1, "解析响应失败: ${e.message}", null, null, null, null, null)
                }
            }
            
        } catch (e: IOException) {
            logger.error("获取上传凭证网络异常", e)
            return UploadCredentialResponse(-1, "网络请求失败: ${e.message}", null, null, null, null, null)
        } catch (e: Exception) {
            logger.error("获取上传凭证失败", e)
            return UploadCredentialResponse(-1, "请求失败: ${e.message}", null, null, null, null, null)
        }
    }
    
    /**
     * 使用凭证上传文件
     */
    private fun uploadFileWithCredential(
        file: MultipartFile, 
        fileName: String, 
        credential: UploadCredentialResponse
    ): FileUploadResult {
        
        if (credential.url == null || credential.token == null || credential.authorization == null || credential.cosFileId == null) {
            return FileUploadResult(false, "上传凭证信息不完整: url=${credential.url}, token=${credential.token != null}, authorization=${credential.authorization != null}, cosFileId=${credential.cosFileId}")
        }
        
        try {
            // 构建multipart/form-data - 使用OkHttp3
            val requestBody = MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("key", fileName)
                .addFormDataPart("Signature", credential.authorization)
                .addFormDataPart("x-cos-security-token", credential.token)
                .addFormDataPart("x-cos-meta-fileid", credential.cosFileId)
                .addFormDataPart(
                    "file",
                    file.originalFilename ?: fileName,
                    file.bytes.toRequestBody((file.contentType ?: "application/octet-stream").toMediaType())
                )
                .build()
            
            val request = Request.Builder()
                .url(credential.url)
                .post(requestBody)
                .build()
            
            logger.info("开始上传文件到COS: ${credential.url}")
            logger.info("表单参数: key=$fileName, cosFileId=${credential.cosFileId}")
            
            httpClient.newCall(request).execute().use { response ->
                val responseBodyString = response.body?.string()
                
                logger.info("COS响应状态: ${response.code}")
                logger.info("COS响应内容: $responseBodyString")

                return if (response.isSuccessful) {
                    FileUploadResult(
                        success = true,
                        message = "上传成功",
                        fileId = credential.fileId,
                        cosFileId = credential.cosFileId,
                        url = credential.url
                    )
                } else {
                    FileUploadResult(false, "上传失败，HTTP状态码: ${response.code}, 响应: $responseBodyString")
                }
            }
            
        } catch (e: IOException) {
            logger.error("上传文件到云存储网络异常", e)
            return FileUploadResult(false, "上传文件网络异常: ${e.message}")
        } catch (e: Exception) {
            logger.error("上传文件到云存储失败", e)
            return FileUploadResult(false, "上传文件失败: ${e.message}")
        }
    }
    
    
    /**
     * 验证文件类型是否为音频
     */
    fun isAudioFile(file: MultipartFile): Boolean {
        val contentType = file.contentType
        return contentType != null && contentType.startsWith("audio/")
    }
    
    /**
     * 验证文件大小（最大10MB）
     */
    fun isValidFileSize(file: MultipartFile, maxSizeMB: Long = 10): Boolean {
        val maxSizeBytes = maxSizeMB * 1024 * 1024
        return file.size <= maxSizeBytes
    }

    /**
     * 验证文件类型是否为图片
     */
    fun isImageFile(file: MultipartFile): Boolean {
        val contentType = file.contentType
        return contentType != null && contentType.startsWith("image/")
    }

    /**
     * 上传图片文件到微信云（exam_image 目录）
     */
    fun uploadImageFile(file: MultipartFile, originalFileName: String): FileUploadResult {
        return try {
            val storagePath = "exam_image/${System.currentTimeMillis()}_$originalFileName"
            logger.info("开始上传图片文件，路径: $storagePath")

            val credential = getUploadCredential(storagePath)
            if (credential.errcode != 0) {
                logger.error("获取上传凭证失败: ${credential.errmsg}")
                FileUploadResult(false, credential.errmsg ?: "获取上传凭证失败")
            } else {
                uploadFileWithCredential(file, storagePath, credential)
            }
        } catch (e: Exception) {
            logger.error("上传图片异常: $originalFileName", e)
            FileUploadResult(false, "上传图片异常: ${e.message}")
        }
    }
}
